#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <unistd.h>
#include <semaphore.h>

#define ARRAY_SIZE 6
/**
 * 链表节点
 */
typedef struct _node_t {
    int data;
    struct _node_t * next;
} node_t;

node_t * head = NULL;

// 互斥锁
pthread_mutex_t mutex;
// 条件变量
sem_t sem_producer;
sem_t sem_customer;
/**
 * 改变条件的 线程
 * @param arg
 * @return
 */
void * producer(void * arg){
    //
    while(1){
        //申请一个资源
        sem_wait(&sem_producer);
        //分配节点空间
        node_t * nn = malloc(sizeof(node_t));
        if(nn == NULL){
            break;
        }
        memset(nn,0, sizeof(node_t));
        nn->data = random() % 100 + 1;
        nn->next = NULL;
        nn->next = head;
        //头部插入法
        nn->next = head;
        head = nn;
        printf("producer : %d\n",nn->data);
        //通知消费者
        sem_post(&sem_customer);

        sleep(random() % 3 +1);
    }
    pthread_exit(NULL);
}

/**
 * 等待条件的 线程
 * @param arg
 * @return
 */
void * customer(void * arg){
    node_t * temp = NULL;
    while(1){
        //申请资源
        sem_wait(&sem_customer);
        //表示条件不满足
        if(head == NULL){

        }
        temp = head;
        head = head->next;
        printf("customer : %d\n",temp->data);
        free(temp);

        //释放资源
        sem_post(&sem_producer);

    }
    return NULL;
}

/**
 * 信号量 的 生产消费模型
 * @return
 */
int main(){
    pthread_t tids[ARRAY_SIZE];
    int ret = -1;
    //设置随机种子
    srandom(getpid());
    // 初始化
    ret = sem_init(&sem_producer,0,8);
    ret = sem_init(&sem_customer,0,0);
    // 创建 4个生产者，4个消费者
    for (int i = 0; i < ARRAY_SIZE; ++i) {
        if(i < 2){
            pthread_create(&tids[i],NULL,producer,(void *)(long)i);
        }
        else{
            pthread_create(&tids[i],NULL,customer,(void *)(long)i);
        }
    }

    // 回收线程资源
    for (int i = 0; i < ARRAY_SIZE; ++i) {
        pthread_join(tids[i],NULL);
    }

    // 销毁
    sem_destroy(&sem_producer);
    sem_destroy(&sem_customer);

    printf("main exit...\n");
    return 0;
}
